package ve
{
	import iks.utils.geom.*;
	
	/**
	 * 驾驶的机车类
	 * @author StefanieKaka
	 */
	public class SteeredVehicle extends Vehicle 
	{
		/**
		 * 构造函数
		 */
		public function SteeredVehicle(color : uint = 0x000000) 
		{
			super(color);
			m_steeringForce = new Vector2D();
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 公共域
///////////////////////////////////////////////////////////////////////////////////////////////////

		/**
		 * 获取/设置最大的转向力
		 */
		public function get maxForce() : Number
		{
			return m_maxForce;
		}
		
		public function set maxForce(value : Number) : void
		{
			m_maxForce = value;
		}
		
		/**
		 * 漫游距离
		 */
		public function get wanderDistance() : Number
		{
			return m_wanderDistance;
		}
		
		public function set wanderDistance(value : Number) : void
		{
			m_wanderDistance = value;
		}
		
		/**
		 * 漫游半径
		 */
		public function get wanderRadius() : Number
		{
			return m_wanderRadius;
		}
		
		public function set wanderRadius(value : Number) : void
		{
			m_wanderRadius = value;
		}
		
		/**
		 * 漫游角度的随机范围
		 */
		public function get wanderRange() : Number
		{
			return m_wanderRanger;
		}
		
		public function set wanderRange(value : Number) : void
		{
			m_wanderRanger = value;
		}
		
		/**
		 * 路径索引
		 */
		public function get pathIndex() : int
		{
			return m_pathIndex;
		}
		
		public function set pathIndex(value : int) : void
		{
			m_pathIndex = value;
		}
		
		/**
		 * 到达路径点的阈值
		 */
		public function get pathThreshold() : Number
		{
			return m_pathThreshold;
		}
		
		public function set pathThreshold(value : Number) : void
		{
			m_pathThreshold = value;
		}
		
		/**
		 * 视野距离
		 */
		public function get inSightDist() : Number
		{
			return m_inSightDist;
		}
		
		public function set inSightDist(value : Number) : void
		{
			m_inSightDist = value;
		}
		
		/**
		 * 最近距离
		 */
		public function get tooCloseDist() : Number
		{
			return m_tooCloseDist;
		}
		
		public function set tooCloseDist(value : Number) : void
		{
			m_tooCloseDist = value;
		}
		
		/// 搜寻行为
		public function seek(target : Vector2D) : void
		{
			// ①: 计算出到达目的速度
			var desiredVelocity : Vector2D = target.subtract(m_position);
			
			// ②: 归一化, 保证方向不变
			desiredVelocity.normalize();
			
			// ③: 计算期望速度所能达到的最大值
			desiredVelocity.mutiply(m_maxSpeed);
			
			// ④: 得到 达到 期望速度需要的 force 速度
			var force : Vector2D = desiredVelocity.subtract(m_velocity);
			m_steeringForce.add(force);
		}
		
		/// 逃避行为
		public function flee(target : Vector2D) : void
		{
			// ①: 计算出到达目的速度
			var desiredVelocity : Vector2D = target.subtract(m_position);
			
			// ②: 归一化, 保证方向不变
			desiredVelocity.normalize();
			
			// ③: 计算期望速度所能达到的最大值
			desiredVelocity.mutiply(m_maxSpeed);
			
			// ④: 得到 达到 期望速度需要的 force 速度, 到目前为止, 与 seek 函数功能都一致
			var force : Vector2D = desiredVelocity.subtract(m_velocity);
			
			// ⑤: 向预期的方向反响行驶
			m_steeringForce.subtract(force);
		}
		
		/// 到达行为
		public function arrive(target : Vector2D) : void
		{
			var dist : Number = m_position.distance(target);
			
			// ①: 计算出到达目的速度
			var desiredVelocity : Vector2D = target.subtract(m_position);
			
			// ②: 归一化, 保证方向不变
			desiredVelocity.normalize();
			
			// ③: 计算期望速度所能达到的最大值
			if (dist > m_arrivalThreshold)
			{
				desiredVelocity.mutiply(m_maxSpeed);
			}
			else
			{
				// 距离小于阈值时, 将减速向目的地驶去
				desiredVelocity.mutiply(m_maxSpeed * dist / m_arrivalThreshold);
			}
			
			// ④: 得到 达到 期望速度需要的 force 速度
			var force : Vector2D = desiredVelocity.subtract(m_velocity);
			m_steeringForce.add(force);
		}

		/// 追捕行为
		public function pursue(target : Vehicle) : void
		{
			// ①: 计算前瞻时间, 即 自身 到达 target 当前位置所需的时间
			var lookAheadTime : Number = m_position.distance(target.position) / m_maxSpeed;
			
			// ②: 根据前瞻时间预测 target 将来的位置
			var predictedTarget : Vector2D = target.position.clone().add(target.velocity.clone().mutiply(lookAheadTime));
			
			// ③: 对预期位置做搜寻行为
			seek(predictedTarget);
		}
		
		/// 躲避行为
		public function evade(target : Vehicle) : void
		{
			// ①: 计算前瞻时间, 即 自身 到达 target 当前位置所需的时间
			var lookAheadTime : Number = m_position.distance(target.position) / m_maxSpeed;
			
			// ②: 根据前瞻时间预测 target 将来的位置
			var predictedTarget : Vector2D = target.position.clone().add(target.velocity.clone().mutiply(lookAheadTime));
			
			// ③: 对预期位置做逃避行为
			flee(predictedTarget);
		}
		
		/// 漫游行为
		public function wander() : void
		{
			var center : Vector2D = m_velocity.clone().normalize().mutiply(m_wanderDistance);
			var offset : Vector2D = new Vector2D();
			offset.length = m_wanderRadius;
			offset.angle = m_wanderAngle;
			m_wanderAngle += Math.random() * m_wanderRanger - m_wanderRanger * 0.5;
			var force : Vector2D = center.add(offset);
			m_steeringForce.add(force);
		}
		
		/// 规避行为
		public function avoid(circles : Vector.<KCircle>) : void
		{
			for (var i : int = 0; i < circles.length; ++i)
			{
				var circle : KCircle = circles[i];
				var heading : Vector2D = m_velocity.clone().normalize();
				
				// 机车 与 圆之间的差量
				var difference : Vector2D = new Vector2D(circle.x, circle.y);
				difference.subtract(m_position);
				
				// 机车速度 与 相对位置向量之间角度
				var dotProd : Number = difference.dotProduct(heading);
				
				// 圆 在 机车的前方
				if (dotProd > 0)
				{
					// 计算触手的数值
					var feeler : Vector2D = heading.clone().mutiply(m_avoidDistance);
					
					// 计算 difference 在 feeler 上的投影
					var projection : Vector2D = heading.clone().mutiply(dotProd);
					
					// 计算 difference 与 feeler 的距离
					// dist1 是 difference 到 feeler 的垂直距离
					var dist1 : Number = projection.clone().subtract(difference).length;
					// dist2 是 difference 与 feeler 两点间的距离
					var dist2 : Number = feeler.clone().subtract(difference).length;
					
					// 触手与圆交叉, 同时投影的数值要小于触手的数值
					if ((dist1 < circle.radius + m_avoidBuffer && projection.length < feeler.length)
					|| dist2 < circle.radius + m_avoidBuffer)
					{
						// 计算转向力的方向
						var force : Vector2D = heading.mutiply(m_maxSpeed);
						force.angle += difference.sign(m_velocity) * Math.PI / 2;
						
						// 计算转向力的大小
						force.mutiply(1.0 - projection.length / feeler.length);
						
						// 累加转向力
						m_steeringForce.add(force);
						
						// 刹车 - 放慢机车的速度, 让它有时间转弯, 越靠近障碍, 越难制动
						m_velocity.mutiply(projection.length / feeler.length);
					}
				}
			}
		}
		
		/// 路径追随
		public function followPath(path : Vector.<Vector2D>, loop : Boolean = false) : void
		{
			if (m_pathIndex >= path.length)
				return;
				
			var wayPoint : Vector2D = path[m_pathIndex];
			if (m_position.distSQ(wayPoint) <= m_pathThreshold * m_pathThreshold)
			{
				if (m_pathIndex == path.length - 1)
				{
					if (loop)
						m_pathIndex = 0;
				}
				else
					++m_pathIndex;
			}
			
			if (m_pathIndex == path.length - 1 && !loop)
				arrive(wayPoint.clone());
			else
				seek(wayPoint.clone());
		}
		
		/// 群聚行为
		public function flock(vehicles : Vector.<Vehicle>) : void
		{
			var averageVelocity : Vector2D = m_velocity.clone();
			var averagePosition : Vector2D = new Vector2D();
			var inSightCount : int = 0;
			
			for (var i : int = 0; i < vehicles.length; ++i)
			{
				var vehicle : Vehicle = vehicles[i];
				if (vehicle != this && inSight(vehicle))
				{
					averageVelocity.add(vehicle.velocity);
					averagePosition.add(vehicle.position);
					
					// 分离
					if (tooClose(vehicle))
						flee(vehicle.position.clone());
					
					++inSightCount;
				}
			}
			
			if (inSightCount > 0)
			{
				// 凝聚
				averagePosition.divide(inSightCount);
				seek(averagePosition);
				
				// 转向力对齐到平均速度方向上
				averageVelocity.divide(inSightCount);
				m_steeringForce.add(averageVelocity.subtract(m_velocity));
			}
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 重写方法
///////////////////////////////////////////////////////////////////////////////////////////////////

		override public function update() : void 
		{
			// 转向力不能超过给定的最大转向力范围
			m_steeringForce.truncate(m_maxForce);
			
			// 质量越大转向力越小
			m_steeringForce.divide(this.mass);
			
			velocity.add(m_steeringForce);
			m_steeringForce = new Vector2D();
			
			super.update();
		}

///////////////////////////////////////////////////////////////////////////////////////////////////
// 私有域
///////////////////////////////////////////////////////////////////////////////////////////////////

		/// 视野
		private function inSight(vehicle : Vehicle) : Boolean
		{
			// 首先判断在视野范围内
			if (m_position.distance(vehicle.position) > m_inSightDist)
				return false;
			
			// 计算 vehicle 对象是否在当前对象前方的 180° 范围内
			var heading : Vector2D = m_velocity.clone().normalize();
			var difference : Vector2D = vehicle.position.clone().subtract(m_position);
			var dotProd : Number = difference.dotProduct(heading);
			
			return dotProd >= 0;
		}
		
		/// 最近距离
		private function tooClose(vehicle : Vehicle) : Boolean
		{
			return m_position.distance(vehicle.position) < m_tooCloseDist;
		}

		private var m_maxForce : Number = 1;
		private var m_steeringForce : Vector2D = null;
		
		private var m_arrivalThreshold : Number = 100;
		
		private var m_wanderAngle : Number = 0;
		private var m_wanderDistance : Number = 10;
		private var m_wanderRadius : Number = 5;
		private var m_wanderRanger : Number = 1;
		
		private var m_avoidDistance : Number = 300;
		private var m_avoidBuffer : Number = 20;
		
		private var m_pathIndex : int = 0;
		private var m_pathThreshold : Number = 20;
		
		private var m_inSightDist : Number = 200;
		private var m_tooCloseDist : Number = 60;
	}

}

































///////////////////////////////////////////////////////////////////////////////////////////////////
// end file